/*
 * Terminador.cpp
 *
 *  Created on: 09/10/2012
 */

#include "Terminador.h"

/**
 * Constructor del terminador.
 * Recibe el tiempo que debe durar la simulacion.
 * Registra los handlers de señales.
 */
Terminador::Terminador(int tiempo)
	: tiempo (tiempo){

	SignalHandler::getInstance()->registrarHandler(SIGINT, this);
	SignalHandler::getInstance()->registrarHandler(SIGTERM, this);

	Log::getInstance()->getInstance()->loguear("Terminador: creado.");
}

/**
 * Destructor del terminador.
 * Elimina los handlers de señales.
 */
Terminador::~Terminador() {
	SignalHandler::getInstance()->removerHandler(SIGINT);
	SignalHandler::getInstance()->removerHandler(SIGTERM);
	SignalHandler::destruir();
}

/**
 * Handler de señales:
 * SIGTERM: Señal que el usuario envia desde fuera de la aplicacion.
 * 		El terminador comienza la finalizacion de la ejecucion ordenadamente.
 * SIGINT: Señal que el usuario envia desde fuera de la aplicacion.
 * 		El terminador comienza la finalizacion de la ejecucion ordenadamente.
 */
int Terminador::handleSignal( int signum ){
	if (signum == SIGTERM){
		Log::getInstance()->loguear("Terminador: me llego SIGTERM. Voy a finalizar.");

	} else if (signum == SIGINT) {
		Log::getInstance()->loguear("Terminador: me llego SIGINT. Voy a finalizar.");

	}
	return 0;
}

/**
 * Metodo que se ejecuta mientras quede tiempo de simulacion.
 */
void Terminador::ejecutar(){
	Log::getInstance()->loguear("Terminador: me duermo " + intToString(this->tiempo) + " segundos.");
	int tiempoRestante = sleep(this->tiempo);
	if (tiempoRestante == 0){
		Log::getInstance()->imprimir("Terminador: se terminó el tiempo de simulación.");
	} else {
		Log::getInstance()->imprimir("Terminador: el usuario detiene la simulación.");
	}
	this->terminar();
}

/**
 * Metodo que envia una señal SIGUSR1 a el administrador para que cierre los estacionamientos.
 * Espera a que se muera el administrador y luego finaliza el proceso de consulta.
 */
void Terminador::terminar(){
	Log::getInstance()->loguear("Terminador: comienzo el envio de señales para finalizar el programa.");
	int state;
	
	// Se mata el administrador
	kill(pidAdministrador, SIGUSR1);
	waitpid(pidAdministrador, &state, 0);

	// Se mata el proceso de consulta.
	kill(pidConsulta, SIGUSR1);
	waitpid(pidConsulta, &state, 0);
}

void Terminador::setPidConsulta(pid_t pid){
	this->pidConsulta = pid;
}

void Terminador::setPidAdministrador(pid_t pid){
	this->pidAdministrador = pid;
}
